package com.wf.gatewayService.config;

import cn.hutool.core.util.StrUtil;
import com.auth0.jwt.exceptions.AlgorithmMismatchException;
import com.auth0.jwt.exceptions.SignatureVerificationException;
import com.auth0.jwt.exceptions.TokenExpiredException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.wf.apicommons.utils.CodeEnum;
import com.wf.apicommons.utils.CommonResult;
import com.wf.apicommons.utils.JWTUtils;
import com.wf.apicommons.utils.MD5Util;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

/**
 * @Description: token鉴权过滤
 */
@Component
@Slf4j
public class AuthJwtFilter implements GlobalFilter, Ordered {

    /**
     * 无需鉴权的URL
     */
    private static  final String[] skipAuthUrls={"/user/management/user/login","/user/management/user/register","/user/management/user/getCode"};

    @Override
    public Mono<Void>
    filter(ServerWebExchange exchange,GatewayFilterChain chain) {
        //获取请求url地址
        String url =exchange.getRequest().getURI().getPath();
        //跳过不需要验证的路径
        if (null != skipAuthUrls && isSkipUrl(url)) {
            return chain.filter(exchange);
        }

        //从请求头中取得token
        String token = exchange.getRequest().getHeaders().getFirst("Authorization");
        //标识当前请求来源于网关，屏蔽非法请求

        exchange.getRequest().mutate().header("RequestSource", MD5Util.encryption("request_from_gateway")).build();

        CommonResult<String> result=new CommonResult<>();

        //判断token是否为null
        if(!StrUtil.hasBlank(token)){
            try{
                //验证令牌
                JWTUtils.verify(token);
                //放行请求
                return chain.filter(exchange);
            } catch (SignatureVerificationException e) {
                //无效签名
                result.setCode(CodeEnum.JWT_INVALID.getCode());
                result.setData(CodeEnum.JWT_INVALID.getMessage());
            } catch (TokenExpiredException e) {
                //token过期
                result.setCode(CodeEnum.JWT_OVERDUE.getCode());
                result.setData(CodeEnum.JWT_OVERDUE.getMessage());
            } catch (AlgorithmMismatchException e) {
                //token算法不一致\
                result.setCode(CodeEnum.JWT_ALGORITHM_INCONSISTENCY.getCode());
                result.setData(CodeEnum.JWT_ALGORITHM_INCONSISTENCY.getMessage());
            } catch (Exception e) {
                //token失效
                result.setCode(CodeEnum.JWT_LOSE_EFFECT.getCode());
                result.setData(CodeEnum.JWT_LOSE_EFFECT.getMessage());
            }
        }else{
            //无效签名
            result.setCode(CodeEnum.JWT_INVALID.getCode());
            result.setData(CodeEnum.JWT_INVALID.getMessage());
        }



        return getFailResponse(exchange.getResponse(),result);
    }

    @Override
    public int getOrder() {
        return 0;
    }

    /**
     * 判断当前访问的url是否开头URI是在配置的忽略
     * url列表中
     *
     * @param url
     * @return
     */
    public boolean isSkipUrl(String url) {
        for (String skipAuthUrl : skipAuthUrls) {
            if (url.startsWith(skipAuthUrl)) {
                return true;
            }
        }
        return false;
    }


    /**
     * 获取失败返回信息
     * @param response
     * @param result
     * @return
     */
    private Mono<Void> getFailResponse(ServerHttpResponse response, CommonResult<String> result) {
        DataBuffer buffer = null;
        try {
        //将map转化成json，response使用的是Jackson
        String resultStr = new ObjectMapper().writeValueAsString(result);
            response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
            response.getHeaders().set("Access-Control-Allow-Origin","*");
            response.setStatusCode(HttpStatus.OK);
            response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
            buffer = response.bufferFactory().wrap(resultStr.getBytes("UTF-8"));
        } catch (Exception e) {
            log.info("gateway鉴权错误，{}",e.getMessage());
            e.printStackTrace();
        }
        return response.writeWith(Flux.just(buffer));
    }





}
